package com.smzd.ccms.core;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 请求和视图之间的配置，用于在内存中cache所有的配置，提高系统运行效率。
 * 
 * @author YuZhongda
 * 
 */
public class ViewMapper implements Serializable {
	private static final long serialVersionUID = -528737569533884381L;
	private static final Pattern PAGE_REQUEST_PATTERN = Pattern.compile("\\{.+?\\}");
	/**
	 * 清楚
	 */
	private String uri;
	/**
	 * 前缀
	 */
	private String prefix;

	/**
	 * 站点名称，固定字符串
	 */
	private String site;
	/**
	 * 频道名称，固定字符串
	 */
	private String channel;
	/**
	 * 请求名称，对应视图，允许使用{}来定义变量
	 */
	private String page;
	/**
	 * 视图路径
	 */
	private String view;
	/**
	 * 请求的正则表达式字符串，对应page
	 */
	private String uri_regexp;
	/**
	 * 请求的正则表达式中的变量数量
	 */
	private int variableCount = 0;
	/**
	 * 请求的正则表达式中固定的部分长度
	 */
	private int fixCount = 0;
	/**
	 * 请求中的变量名称
	 */
	private String[] variables;

	private Pattern pattern;

	private EntityWrapper entityWrapper = new EntityWrapper();
	
	public ViewMapper(String prefix, String site, String channel, String page, String view) {
		this.uri = "/" + prefix + "/" + site + "/" + channel + "/" + page;
		this.prefix = prefix;
		this.site = site;
		this.channel = channel;
		this.page = page;
		this.view = view;
		initRequestPattern();
	}

	private void initRequestPattern() {
		Matcher matcher = PAGE_REQUEST_PATTERN.matcher(page);
		StringBuilder sb = new StringBuilder();
		int index = 0;
		boolean regexpFlag = false;
		List<String> pathVars = new ArrayList<>();
		variableCount = 0;
		while (matcher.find(index)) {
			regexpFlag = true;
			int start = matcher.start();
			int end = matcher.end();
			if (start > index) {
				String plain = page.substring(index, start);
				if (plain.indexOf(".") >= 0) {
					plain = plain.replaceAll("\\.", "\\\\.");
				}
				if (plain.indexOf("-") >= 0) {
					plain = plain.replaceAll("\\-", "\\\\-");
				}
				sb.append(plain);
			}
			sb.append("(.+?)");
			variableCount++;
			String variable = page.substring(start + 1, end - 1);
			// System.out.println("variable=[" + variable + "]");
			pathVars.add(variable);
			index = end;
		}
		if (page.length() > index) {
			String plain = page.substring(index);
			if (regexpFlag) {
				if (plain.indexOf(".") >= 0) {
					plain = plain.replaceAll("\\.", "\\\\.");
				}
				if (plain.indexOf("-") >= 0) {
					plain = plain.replaceAll("\\-", "\\\\-");
				}
			}
			sb.append(plain);
		}
		this.uri_regexp = sb.toString();
		this.fixCount = this.uri_regexp.length() - (5 * this.variableCount);
		if (regexpFlag) {
			this.pattern = Pattern.compile(this.uri_regexp);
			this.variables = new String[pathVars.size()];
			pathVars.toArray(this.variables);
		}
	}

	/**
	 * 给出一个URL的Pattern来，用于确认一个请求应该使用哪个视图。
	 * 
	 * @param uri
	 *            pattern，支持使用{}来定义路径变量，路径变量将在创建mapper的时候得到，
	 *            并且在匹配成功的时候给出这个参数实际对应的值。
	 * @param view
	 *            视图
	 */
	public ViewMapper(String uri, String view) {
		if (!uri.startsWith("/")) {
			throw new RuntimeException("不正确的初始化URI！uri=" + uri);
		}
		String[] strings = uri.split("/");
		if (strings.length != 5) {
			throw new RuntimeException("不正确的初始化URI！uri=" + uri);
		}
		this.uri = uri;
		this.prefix = strings[1];
		this.site = strings[2];
		this.channel = strings[3];
		this.page = strings[4];
		this.view = view;
		initRequestPattern();
	}

	public static void main(String[] args) {
		// 创建ViewMapper
		ViewMapper vp = new ViewMapper("/p/site/test/page-abcdefg-{xz}-{ab}.html", "");
		// 用ViewMapper来匹配请求，结果放在ViewMapResult里面
		ViewMapResult r = vp.match("/p/site/test/page-abcdefg-xyzfffffff-aaabbb.html");
		// 看看是不是匹配成功
		System.out.println(r.isMatch());
		if (r.isMatch()) {
			// 匹配成功的话，如果viewmapper有路径参数，
			// 则会根据其路径参数将对应的值放进viewmapresult里面，
			// 同时路径参数也会塞进去，其实是viewmapper里面的，只是为了使用方便
			String[] values = r.getValues();
			String[] variables = vp.getVariables();// 也可以从result里面获取
			for (int i = 0; i < values.length; i++) {
				System.out.println(variables[i] + "=" + values[i]);
			}
		} else {
			System.out.println(r.getMessage());
		}
	}

	public ViewMapResult match(String uri) {
		ViewMapResult result = new ViewMapResult();
		result.setMapper(this);
		if (this.variableCount == 0) {
			result.setMatch(this.uri.equals(uri));
			return result;
		}
		result.setMatch(false);
		if (!uri.startsWith("/")) {
			result.setMessage("不正确的初始化URI！uri=" + uri);
			return result;
		}
		String[] strings = uri.split("/");
		if (strings.length != 5) {
			result.setMessage("不正确的初始化URI！uri=" + uri);
			return result;
		}
		if (!prefix.equalsIgnoreCase(strings[1])) {
			result.setMessage("前缀不相符！uri=" + uri);
			return result;
		}
		if (!site.equalsIgnoreCase(strings[2])) {
			result.setMessage("前缀不相符！uri=" + uri);
			return result;
		}
		if (!channel.equalsIgnoreCase(strings[3])) {
			result.setMessage("前缀不相符！uri=" + uri);
			return result;
		}
		String page = strings[4];
		Matcher matcher = this.pattern.matcher(page);
		if (matcher.matches()) {
			int count = variables.length;
			String[] values = new String[count];
			for (int i = 0; i < count; i++) {
				values[i] = matcher.group(i + 1);
			}
			result.setMatch(true);
			result.setValues(values);
			result.setVariables(variables);
		} else {
			result.setMatch(false);
		}
		return result;
	}

	public String getSite() {
		return site;
	}

	public void setSite(String site) {
		this.site = site;
	}

	public String getChannel() {
		return channel;
	}

	public void setChannel(String channel) {
		this.channel = channel;
	}

	public String getPage() {
		return page;
	}

	public void setPage(String page) {
		this.page = page;
	}

	public String getView() {
		return view;
	}

	public void setView(String view) {
		this.view = view;
	}

	public String getUri_regexp() {
		return uri_regexp;
	}

	public void setUri_regexp(String uri_regexp) {
		this.uri_regexp = uri_regexp;
	}

	public int getVariableCount() {
		return variableCount;
	}

	public void setVariableCount(int variableCount) {
		this.variableCount = variableCount;
	}

	public String[] getVariables() {
		return variables;
	}

	public void setVariables(String[] variables) {
		this.variables = variables;
	}

	public Pattern getPattern() {
		return pattern;
	}

	public void setPattern(Pattern pattern) {
		this.pattern = pattern;
	}

	public String getPrefix() {
		return prefix;
	}

	public void setPrefix(String prefix) {
		this.prefix = prefix;
	}

	public int getFixCount() {
		return fixCount;
	}

	public void setFixCount(int fixCount) {
		this.fixCount = fixCount;
	}

	public String getUri() {
		return uri;
	}

	public void setUri(String uri) {
		this.uri = uri;
	}

	public EntityWrapper getEntityWrapper() {
		return entityWrapper;
	}

	public void setEntityWrapper(EntityWrapper entityWrapper) {
		this.entityWrapper = entityWrapper;
	}
}
